#include "wire.h"
#include <stdio.h>
#include "micros.h"
// ------------------------
// 私有函数声明
// ------------------------

static void wire_enable_clock(I2C_TypeDef* I2Cx);
static void wire_configure_gpio(I2C_TypeDef* I2Cx);
static uint8_t wire_wait_idle(I2C_TypeDef* i2c, uint32_t timeout);
static uint8_t wire_wait_event(I2C_TypeDef* i2c, uint32_t event, uint32_t timeout);

// ------------------------
// I2C 总线强制恢复（根据 wire->i2c 自动判断）
// ------------------------

void Wire_force_reset(Wire* wire) {
    if (!wire || !wire->i2c) return;

    I2C_TypeDef* i2c = wire->i2c;
    GPIO_InitTypeDef GPIO_InitStruct;
    GPIO_TypeDef* GPIOx;
    uint16_t SCL_Pin, SDA_Pin;

    // 根据 I2C 选择对应的 GPIO 和引脚
    if (i2c == I2C1) {
        RCC_APB1PeriphClockCmd(RCC_APB1Periph_I2C1, DISABLE);
        RCC_APB1PeriphClockCmd(RCC_APB1Periph_I2C1, ENABLE); // 重新使能时钟
        GPIOx = GPIOB;
        SCL_Pin = GPIO_Pin_6;
        SDA_Pin = GPIO_Pin_7;
    } else if (i2c == I2C2) {
        RCC_APB1PeriphClockCmd(RCC_APB1Periph_I2C2, DISABLE);
        RCC_APB1PeriphClockCmd(RCC_APB1Periph_I2C2, ENABLE);
        GPIOx = GPIOB;
        SCL_Pin = GPIO_Pin_10;
        SDA_Pin = GPIO_Pin_11;
    } else {
        return;
    }

    // 1. 关闭 I2C 外设
    I2C_Cmd(i2c, DISABLE);
    I2C_DeInit(i2c);

    // 2. 使能 GPIO 时钟
    RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB, ENABLE);

    // 3. 配置 SCL/SDA 为推挽输出
    GPIO_InitStruct.GPIO_Mode = GPIO_Mode_Out_PP;
    GPIO_InitStruct.GPIO_Speed = GPIO_Speed_50MHz;
    GPIO_InitStruct.GPIO_Pin = SCL_Pin | SDA_Pin;
    GPIO_Init(GPIOx, &GPIO_InitStruct);

    // 4. 初始高电平
    GPIO_SetBits(GPIOx, SCL_Pin | SDA_Pin);

    // 5. 产生最多 9 个时钟脉冲，释放总线
    for (int i = 0; i < 9; i++) {
        // SCL 低
        GPIO_ResetBits(GPIOx, SCL_Pin);
        for (volatile int j = 0; j < 100; j++);

        // SCL 高
        GPIO_SetBits(GPIOx, SCL_Pin);
        for (volatile int j = 0; j < 100; j++);

        // 检查 SDA 是否释放
        if (GPIO_ReadInputDataBit(GPIOx, SDA_Pin) == Bit_SET) {
            break;
        }
    }

    // 6. 重新配置为 I2C 复用开漏
    GPIO_InitStruct.GPIO_Pin = SCL_Pin | SDA_Pin;
    GPIO_InitStruct.GPIO_Mode = GPIO_Mode_AF_OD;
    GPIO_InitStruct.GPIO_Speed = GPIO_Speed_50MHz;
    GPIO_Init(GPIOx, &GPIO_InitStruct);

    // 7. 重新初始化 I2C
    Wire_begin(wire, i2c, 50000); // 默认 50kHz
}

// ------------------------
// 初始化
// ------------------------

void Wire_begin(Wire* wire, I2C_TypeDef* I2Cx, uint32_t speed) {
    if (!wire) return;

    wire->i2c = I2Cx;
    wire->tx_idx = 0;
    wire->rx_idx = 0;

    wire_enable_clock(I2Cx);
    wire_configure_gpio(I2Cx);

    I2C_InitTypeDef I2C_InitStruct;
    I2C_DeInit(I2Cx);

    I2C_InitStruct.I2C_Mode = I2C_Mode_I2C;
    I2C_InitStruct.I2C_DutyCycle = I2C_DutyCycle_2;
    I2C_InitStruct.I2C_OwnAddress1 = 0x00;
    I2C_InitStruct.I2C_Ack = I2C_Ack_Enable;
    I2C_InitStruct.I2C_AcknowledgedAddress = I2C_AcknowledgedAddress_7bit;
    I2C_InitStruct.I2C_ClockSpeed = speed;

    I2C_Init(I2Cx, &I2C_InitStruct);
    I2C_Cmd(I2Cx, ENABLE);
	
}

// ------------------------
// 发送流程
// ------------------------

void Wire_beginTransmission(Wire* wire, uint8_t address) {
    if (!wire) return;
    wire->tx_idx = 0;
    if (wire->tx_idx < WIRE_BUFSIZ) {
        wire->tx_buf[wire->tx_idx++] = address;
    }
}

void Wire_write(Wire* wire, uint8_t data) {
    if (!wire || wire->tx_idx >= WIRE_BUFSIZ) return;
    wire->tx_buf[wire->tx_idx++] = data;
}

int Wire_endTransmission(Wire* wire, uint8_t sendStop) {
    if (!wire || wire->tx_idx == 0) return -1;

    I2C_TypeDef* i2c = wire->i2c;
    uint8_t addr = wire->tx_buf[0];
    uint8_t* data = &wire->tx_buf[1];
    uint8_t len = wire->tx_idx - 1;

    // 等待总线空闲（仅在非 Repeated Start 前使用）
    if (!wire_wait_idle(i2c, 100000)) goto fail;

    // START
    I2C_GenerateSTART(i2c, ENABLE);
    if (!wire_wait_event(i2c, I2C_EVENT_MASTER_MODE_SELECT, 1)) goto fail;

    // 发送地址（写）
    I2C_Send7bitAddress(i2c, addr << 1, I2C_Direction_Transmitter);
    if (!wire_wait_event(i2c, I2C_EVENT_MASTER_TRANSMITTER_MODE_SELECTED, 1)) goto fail;

    // 发送数据
    for (uint8_t i = 0; i < len; i++) {
        I2C_SendData(i2c, data[i]);
        if (!wire_wait_event(i2c, I2C_EVENT_MASTER_BYTE_TRANSMITTING, 1)) goto fail;
    }

    if (sendStop) {
        I2C_GenerateSTOP(i2c, ENABLE);
    } else {
		// 发送 START
		I2C_GenerateSTART(i2c, ENABLE);
		if (!wire_wait_event(i2c, I2C_EVENT_MASTER_MODE_SELECT, 1)) { printf("e4\n"); goto fail; }
	}

    wire->tx_idx = 0;
    return 0;

fail:
    I2C_GenerateSTOP(i2c, ENABLE);
	Wire_force_reset(wire);
    wire->tx_idx = 0;
    return -1;
}

// ------------------------
// 接收流程
// ------------------------

uint8_t Wire_requestFrom(Wire* wire, uint8_t address, uint8_t quantity) {
    if (!wire || quantity == 0 || quantity > WIRE_BUFSIZ) return 0;

    I2C_TypeDef* i2c = wire->i2c;
    uint8_t received = 0;
    uint8_t i = 0;

    I2C_Send7bitAddress(i2c, address << 1, I2C_Direction_Receiver);
    if (!wire_wait_event(i2c, I2C_EVENT_MASTER_RECEIVER_MODE_SELECTED, 1)) {
        //printf("e5\n");
        goto fail;
    }

    do {
        if (i == quantity - 1) {
            I2C_AcknowledgeConfig(i2c, DISABLE);
            I2C_GenerateSTOP(i2c, ENABLE);
        }

        if (!wire_wait_event(i2c, I2C_EVENT_MASTER_BYTE_RECEIVED, 1)) {
            //printf("e6: Timeout at byte %d\n", i);
            goto fail;  // 改为 goto fail，统一清理
        }

        // 可选：检查 NACK
        if (I2C_GetFlagStatus(i2c, I2C_FLAG_AF)) {
            //printf("e7: Ack Failure at byte %d\n", i);
            I2C_ClearFlag(i2c, I2C_FLAG_AF);
            goto fail;
        }

        wire->rx_buf[i] = I2C_ReceiveData(i2c);
        received++;
        i++;

    } while (i < quantity);

    I2C_AcknowledgeConfig(i2c, ENABLE);
    wire->rx_idx = 0;
    return received;

fail:
    I2C_GenerateSTOP(i2c, ENABLE);  // ✅ 确保发送 STOP
    // ✅ 等待总线空闲
    uint32_t start = millis();
    while (I2C_GetFlagStatus(i2c, I2C_FLAG_BUSY)) {
        if (millis() - start > 10) break;  // 最多等 10ms
    }
	Wire_force_reset(wire);
    return 0;
}
//uint8_t Wire_requestFrom(Wire* wire, uint8_t address, uint8_t quantity) {
//    if (!wire || quantity == 0 || quantity > WIRE_BUFSIZ) return 0;

//    I2C_TypeDef* i2c = wire->i2c;
//    uint8_t received = 0;
//	uint8_t i = 0;
//	//此前应该有Wire_endTransmission(wire, 0)，从而已经发出了一个restart

//    // 发送地址（读）
//    I2C_Send7bitAddress(i2c, address << 1, I2C_Direction_Receiver);
//    if (!wire_wait_event(i2c, I2C_EVENT_MASTER_RECEIVER_MODE_SELECTED, 20)) { printf("e5\n"); goto fail; }
//	//从此刻开始，主机开始驱动i2c时序，等待从机发送，因此我们要尽快处理，提前做好停止准备
//	
//	do{
//		
//		if(i == quantity - 1) {
//			I2C_AcknowledgeConfig(i2c,DISABLE);//接收最后一个字节之前，要提前设置非应答和停止
//			I2C_GenerateSTOP(i2c,ENABLE);
//		}
//		if (!wire_wait_event(i2c, I2C_EVENT_MASTER_BYTE_RECEIVED, 20)) {
//            printf("e6: Timeout at byte %d\n", i);
//            break;
//        }
//		// 读取数据
//        wire->rx_buf[i] = I2C_ReceiveData(i2c);
//        received++;
//		i++;
//		
//	} while(i < quantity);
//	
//	I2C_AcknowledgeConfig(I2C2,ENABLE);
//	wire->rx_idx = 0;
//    return received;
//fail:
//    I2C_GenerateSTOP(i2c, ENABLE);
//    return 0;
//}

uint8_t Wire_read(Wire* wire) {
    if (!wire || wire->rx_idx >= WIRE_BUFSIZ) return 0;
    return wire->rx_buf[wire->rx_idx++];
}

// ------------------------
// 快捷函数（带自动恢复）
// ------------------------

int Wire_writeReg(Wire* wire, uint8_t dev_addr, uint8_t reg_addr, uint8_t data) {
    Wire_beginTransmission(wire, dev_addr);
    Wire_write(wire, reg_addr);
    Wire_write(wire, data);
    if (Wire_endTransmission(wire, 1) != 0) {
        Wire_force_reset(wire);  // 失败时恢复
        return -1;
    }
    return 0;
}

int Wire_readReg(Wire* wire, uint8_t dev_addr, uint8_t reg_addr, uint8_t* data) {
    if (!data) return -1;

    // Step 1: 写寄存器地址（Repeated Start）
    Wire_beginTransmission(wire, dev_addr);
    Wire_write(wire, reg_addr);
    if (Wire_endTransmission(wire, 0) != 0) {  // 不发 STOP
        //printf("e1\n");
        Wire_force_reset(wire);
        return -1;
    }

    // Step 2: 读 1 字节
    if (Wire_requestFrom(wire, dev_addr, 1) != 1) {
        //printf("e2\n");
        Wire_force_reset(wire);
        return -1;
    }

    *data = Wire_read(wire);
    return 0;
}

int Wire_readRegs(Wire* wire, uint8_t dev_addr, uint8_t reg_addr, uint8_t* buf, uint8_t len) {
    if (!buf || len == 0 || len > WIRE_BUFSIZ) return -1;

    // Step 1: 写起始地址
    Wire_beginTransmission(wire, dev_addr);
    Wire_write(wire, reg_addr);
    if (Wire_endTransmission(wire, 0) != 0) {
        Wire_force_reset(wire);
        return -1;
    }

    // Step 2: 读 len 字节
    if (Wire_requestFrom(wire, dev_addr, len) != len) {
        Wire_force_reset(wire);
        return -1;
    }

    for (uint8_t i = 0; i < len; i++) {
        buf[i] = Wire_read(wire);
    }
    return 0;
}

// ------------------------
// 私有函数
// ------------------------

static void wire_enable_clock(I2C_TypeDef* I2Cx) {
    if (I2Cx == I2C1) {
        RCC_APB1PeriphClockCmd(RCC_APB1Periph_I2C1, ENABLE);
        RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB, ENABLE);
    } else if (I2Cx == I2C2) {
        RCC_APB1PeriphClockCmd(RCC_APB1Periph_I2C2, ENABLE);
        RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB, ENABLE);
    }
}

static void wire_configure_gpio(I2C_TypeDef* I2Cx) {
    GPIO_InitTypeDef GPIO_InitStruct;
    GPIO_InitStruct.GPIO_Mode = GPIO_Mode_AF_OD;
    GPIO_InitStruct.GPIO_Speed = GPIO_Speed_50MHz;

    if (I2Cx == I2C1) {
//		RCC_APB2PeriphClockCmd(RCC_APB2Periph_AFIO, ENABLE);
//		GPIO_PinRemapConfig(GPIO_Remap_I2C1, ENABLE);
//		GPIO_InitStruct.GPIO_Pin = GPIO_Pin_8 | GPIO_Pin_9;
        GPIO_InitStruct.GPIO_Pin = GPIO_Pin_6 | GPIO_Pin_7; //ckl:b6
        GPIO_Init(GPIOB, &GPIO_InitStruct);
    } else if (I2Cx == I2C2) {
        GPIO_InitStruct.GPIO_Pin = GPIO_Pin_10 | GPIO_Pin_11;//ckl:b10
        GPIO_Init(GPIOB, &GPIO_InitStruct);
    }
}

static uint8_t wire_wait_idle(I2C_TypeDef* i2c, uint32_t timeout) {
    while (I2C_GetFlagStatus(i2c, I2C_FLAG_BUSY)) {
        if (--timeout == 0) return 0;
    }
    return 1;
}
static uint8_t wire_wait_event(I2C_TypeDef* i2c, uint32_t event, uint32_t timeout_ms) {
    uint32_t start = micros();
    while (!I2C_CheckEvent(i2c, event)) {
		uint32_t now = micros();
        if (now - start > timeout_ms * 1000) {
			printf("%d - %d > %d timeout\n",now,start, timeout_ms * 1000);
            return 0;
        }
    }
    return 1;
}
